; graphic.asm
; low-level graphic routines

	.include "common.inc"
	.include "global.inc"
	.include "screen.inc"
	
	.export g_set_frame
	.export g_clr
	.export g_moveto
	.export g_move
	.export g_plot
	.export g_mode
	.export g_vline
	.export g_hline
	.export g_rect
	.export g_block
	.export g_putbm
	
	.exportzp regG

	.segment "ZEROPAGE"
	
regG:	.res 2

	.segment "RODATA"
	
pixmap:
	.byte %10000000, %01000000, %00100000, %00010000
	.byte %00001000, %00000100, %00000010, %00000001
pixbeg:
	.byte %11111111, %01111111, %00111111, %00011111
	.byte %00001111, %00000111, %00000011, %00000001
pixend:
	.byte %00000000, %10000000, %11000000, %11100000
	.byte %11110000, %11111000, %11111100, %11111110
	
	.segment "DATA"
	
gc:		.tag Frame
op:		.byte $00
bsz:	.byte $00, $00
ix:		.byte $00	; lower 3 bits of act x coord
pos:	.byte $00

	.segment "CODE"
	
g_set_frame:
	; A ... screen block
	jsr sg_get_block
	stx gc+Frame::ch_height
	stx gc+Frame::px_height
	sty gc+Frame::ch_length

	ldy #4
sf_mul_height:
	asl gc+Frame::px_height
	rol gc+Frame::px_height+1
	dey
	bne sf_mul_height
	
	jsr sg_address2
	sta gc+Frame::addr
	sty gc+Frame::addr+1
	rts

g_clr:
	; A .. fillbyte
	sta op
	lda gc+Frame::addr
	sta reg0
	lda gc+Frame::addr+1
	sta reg0+1
	ldx #4
	lda #0
	sta bsz+1
	lda gc+Frame::ch_length
clr_mul_l1:
	asl
	rol bsz+1
	dex
	bne clr_mul_l1
	sta bsz
	lda bsz+1
	beq clr_fl_rm
clr_flp_lo:
	ldy #0
	lda op
clr_flp_li:
	sta (reg0), y
	iny
	bne clr_flp_li
	inc reg0+1
	dec bsz+1
	bne clr_flp_lo
clr_fl_rm:
	ldy bsz
	beq g_clr_done
	lda op
clr_flr_l:
	dey
	sta (reg0), y
	bne clr_flr_l	
g_clr_done:
	rts

g_moveto:		; X/Y
				clc
				tya
				adc gc+Frame::addr
				sta regG
				lda #0
				adc gc+Frame::addr+1
				sta regG+1
gm_clc_x:		txa
				lsr a
				lsr a 
				lsr	a
				beq gm_nomvy
				tay
gm_mvy_l1:		jsr step_right
				dey
				bne gm_mvy_l1
gm_nomvy:		txa
				and #7
				sta ix
				rts

step_right:		clc
				lda regG
				adc gc+Frame::px_height
				sta regG
				lda regG+1
				adc gc+Frame::px_height+1
				sta regG+1
				rts

step_left:
	sec
	lda regG
	sbc gc+Frame::px_height
	sta regG
	lda regG+1
	sbc gc+Frame::px_height+1
	sta regG+1
	rts

g_move:
	; X/Y - delta
	tya
	clc
	adc regG
	sta regG
	bcc gm_no_inchi
	inc regG+1
	clc
gm_no_inchi:
	txa
	adc ix
	tax
	jmp gm_clc_x	

g_plot:
	; plot at current position using current mode
	ldx ix
	lda pixmap, x
	ldy #0
	jmp gop

g_hline:
	; X .. width , local: pos .. ch cnt, op .. next ix 
	txa
	clc
	adc ix
	tax
	and #$F8
	beq hl_ch_one
	lsr			; save ch count
	lsr
	lsr
	sta pos
	txa
	and #7
	sta op
	ldy #0		; draw line start
	ldx ix
	lda pixbeg, x
	jsr gop
	ldx pos
	dex
	beq hl_drw_end
hl_solid:		; draw solid part
	jsr step_right
	lda #$FF
	jsr gop
	dex
	bne hl_solid
hl_drw_end:		; draw line end
	jsr step_right
	ldx op
	lda pixend, x
	jmp hl_end
hl_ch_one:		; line start & end in one byte
	stx op
	lda pixend, x
	ldx ix
	and pixbeg, x
hl_end:
	ldy #0
	jsr gop
	ldx op
	stx ix
	rts

g_vline:
	; Y .. height
	ldx ix
	lda pixmap, x
	tax	
	sty op
	ldy #0
vhl_l1:
	txa
	jsr gop
	iny
	cpy op
	bne vhl_l1
	ldx #0
	jmp g_move

	.segment "DATA"
	
reg_save:	.byte $00, $00
ix_save:	.byte $00
dx:			.byte $00
dy:			.byte $00

	.segment "CODE"

g_rect:
	; X/Y
	dex
	stx	dx 
	dey
	sty dy
	jsr save_regG
	jsr g_hline
	ldy dy
	jsr g_vline
	jsr rest_inc_regG
	ldy dy
	dey
	jsr g_vline
	ldx dx
	jsr g_hline
	jmp g_plot
	
g_block:
	stx dx
	sty dy
	jsr save_regG
put_line:
	jsr g_hline
	jsr rest_inc_regG
	ldx dx
	dec dy
	bne put_line
	rts
	
save_regG:
	lda regG
	sta reg_save
	lda regG+1
	sta reg_save+1
	lda ix
	sta ix_save
	rts
	
restore_regG:
	lda reg_save
	sta regG
	lda reg_save+1
	sta regG+1
	lda ix_save
	sta ix
	rts

rest_inc_regG:
	clc
	lda reg_save
	adc #1
	sta regG
	sta reg_save
	lda reg_save+1
	adc #0
	sta regG+1
	sta reg_save+1
	lda ix_save
	sta ix
	rts

	.segment "DATA"
	
shift_buf:		.res MAX_COLS
shift_cnt:		.byte $00
shift_cols:		.byte $00
shift_line:		.byte $00
shregsv:		.res 2

	.segment "CODE"

g_putbm:		; A/X .. bitmap struct (Bitmap) Max Size = 255 Bytes (e.g 120x16)
				sta reg1
				stx reg1+1
				ldy #Bitmap::buf_ptr	; get buf_ptr
				lda (reg1), y
				sta reg0
				iny
				lda (reg1), y
				sta reg0+1
				ldy #Bitmap::height 	; get height
				lda (reg1), y
				sta pos
				ldy #Bitmap::width
				lda (reg1), y
				clc
				adc #7
				lsr
				lsr
				lsr
				sta shift_cols
				ldy #0					; draw bm lines
@gpb_nextln:	sty shift_line
				ldx #0
@gbp_nxtcol:	lda (reg0), y
				sta shift_buf, x
				inx
				cpx shift_cols
				beq @gbp_inifin
				tya
				clc
				adc pos
				tay
				bne @gbp_nxtcol
@gbp_inifin:	lda #0
				sta shift_buf, x
				lda ix
				beq @gpb_noshft
				sta shift_cnt			; shift bm for act pos
@gpb_shftl:		ldx #0
				ldy shift_cols
				iny
				clc
@gpb_shftc:		ror shift_buf, x
				inx
				dey
				bne @gpb_shftc
				dec shift_cnt
				bne @gpb_shftl
@gpb_noshft:	lda regG
				sta shregsv
				lda regG+1
				sta shregsv+1
				ldy shift_line
				ldx #$FF
@gpb_outl:		inx
				lda shift_buf, x		; output line
				jsr gop
				jsr step_right
				cpx shift_cols
				bne @gpb_outl
				lda shregsv
				sta regG
				lda shregsv+1
				sta regG+1
				iny
				cpy pos
				bne @gpb_nextln
				ldy #Bitmap::width
				lda (reg1), y
				tax
				ldy #0
				jmp g_move

	.segment "JMPTABLE"
	
gop_ptr:		.word gop_set

	.segment "CODE"
	
g_mode:
				cmp #GM_CLEAR	; clear
				bne gm1
				lda #<gop_clr
				sta gop_ptr
				lda #>gop_clr
				sta gop_ptr+1
				rts
gm1:			cmp #GM_XOR		; xor
				bne gm2
				lda #<gop_xor
				sta gop_ptr
				lda #>gop_xor
				sta gop_ptr+1
				rts
gm2:			lda #<gop_set	; set
				sta gop_ptr
				lda #>gop_set
				sta gop_ptr+1
				rts
	
gop:			jmp (gop_ptr)
	
gop_set:		ora (regG), y
				sta (regG), y
				rts

gop_clr:		eor #$FF
				and (regG), y
				sta (regG), y
				rts

gop_xor:		eor (regG), y
				sta (regG), y
				rts
	